package org.roguelikedevelopment.dweller.j2se;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageOp;
import java.awt.image.ImageObserver;

import javax.imageio.ImageIO;

import org.roguelikedevelopment.dweller.common.application.DwellerGraphics;
import org.roguelikedevelopment.dweller.common.util.logger.Logger;

public class DwellerJ2SEGraphics implements DwellerGraphics, ImageObserver {
	// the original size of the tiles in the PNGs
	public final byte ORIGINAL_TILE_SIZE = 8;
	
	// display width in pixels
	public int CANVAS_WIDTH;
	// display height in pixels
	public int CANVAS_HEIGHT;
	
	// scaled size of tiles
	public byte TILE_SIZE = 16;
	public int TILES_PER_ROW;
	public int TILES_PER_COLUMN;

	private static boolean usesgraphics = true;

	private Image entities;
	private Image dungeon;
	private Image mask;
	private Image cursor;

	private DwellerJ2SECanvas canvas;
	
	private Graphics2D graphics;
	
	public DwellerJ2SEGraphics(DwellerJ2SECanvas canvas) {
		this.canvas = canvas;
		useNormalTiles();
		loadGraphics();		
		updateSize();
	}
	/**
	 * Tells the canvas to use a normal size version of tiles
	 * Reloads tiles and recalculates screen dimensions
	 */
	public void useNormalTiles() {
		if(TILE_SIZE == ORIGINAL_TILE_SIZE) {
			return;
		}
		TILE_SIZE = ORIGINAL_TILE_SIZE;
		if(usesgraphics) {
			loadGraphics();
		}
		else {
			loadASCII();
		}
		updateSize();
	}

	/**
	 * Tells the canvas to use a large version of tiles
	 * Reloads tiles and recalculates screen dimensions
	 */
	public void useLargeTiles() {
		if(TILE_SIZE != ORIGINAL_TILE_SIZE) {
			return;
		}
		TILE_SIZE = ORIGINAL_TILE_SIZE * 2;
		if(usesgraphics) {
			loadGraphics();
		}
		else {
			loadASCII();
		}
		updateSize();
	}	
	
	
	/**
	 * Loads graphical tiles
	 */
	public void loadGraphics() {
		usesgraphics = true;
		entities = loadImage("entities_g.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		dungeon = loadImage("dungeon_g.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		mask = loadImage("mask.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		cursor = loadImage("cursor.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
	}
	
	/**
	 * Loads ascii tiles
	 */
	public void loadASCII() {
		usesgraphics = false;
		entities = loadImage("entities_t.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		dungeon = loadImage("dungeon_t.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		mask = loadImage("mask.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
		cursor = loadImage("cursor.png", TILE_SIZE / ORIGINAL_TILE_SIZE);
	}	
	
	public void updateSize() {
		CANVAS_WIDTH = canvas.getWidth();
		CANVAS_HEIGHT = canvas.getHeight();
		TILES_PER_ROW = 1 + CANVAS_WIDTH / TILE_SIZE;
		TILES_PER_COLUMN = 1 + CANVAS_HEIGHT / TILE_SIZE;
	}
	
	/**
	 * Loads an image
	 * @param filename Filename of the image to load
	 * @param scale Scale of the loaded image. The loaded image's width and height is multiplied with the scale
	 * @return The loaded image
	 */
	public Image loadImage(String filename, int scale) {
		BufferedImage image;
		try {		
			image = ImageIO.read(Thread.currentThread().getContextClassLoader().getResource(filename));
		}
		catch (Exception e) {
			e.printStackTrace();
			return null;
		}

		BufferedImageOp op = new AffineTransformOp(
			AffineTransform.getScaleInstance(scale, scale),
			new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)
		);

		BufferedImage dst = op.filter(image, null);
		return dst;
	}
	
	public void setGraphics(Graphics2D graphics) {
		this.graphics = graphics;
	}
	
	@Override
	public void clearTile(int x, int y) {
		graphics.setColor(Color.BLACK);
		graphics.fillRect(x, y, TILE_SIZE, TILE_SIZE);
	}

	@Override
	public void drawCursor(int x, int y) {
		drawTile(cursor, 0, x, y);
	}

	@Override
	public void drawDungeon(int tileindex, int x, int y) {
		drawTile(dungeon, tileindex, x, y);
	}

	@Override
	public void drawEntity(int tileindex, int x, int y) {
		drawTile(entities, tileindex, x, y);
	}

	@Override
	public void drawFogOfWarMask(int x, int y) {
		drawTile(mask, 0, x, y);
	}
	
	private final void drawTile(Image tiles, int tileindex, int screenX, int screenY) {
		graphics.setClip(screenX, screenY, TILE_SIZE, TILE_SIZE);	
		int imageX = (tileindex % 16) * TILE_SIZE;
		int imageY = (tileindex / 16) * TILE_SIZE;
		graphics.drawImage(tiles, screenX - imageX, screenY - imageY, this);
		graphics.setClip(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
	}

	@Override
	public void drawLine(int rgb, int x1, int y1, int x2, int y2) {
		graphics.setColor(new Color(rgb));
		graphics.drawLine(x1, y1, x2, y2);
	}

	@Override
	public void drawRect(int rgb, int x, int y, int width, int height) {
		graphics.setColor(new Color(rgb));
		graphics.drawRect(x, y, width, height);
	}

	@Override
	public void drawString(String str, int rgb, int x, int y) {
		graphics.setColor(new Color(rgb));
		graphics.drawString(str, x, y + canvas.getCharacterHeight() - 3);
	}

	@Override
	public void fillRect(int rgb, int x, int y, int width, int height) {
		graphics.setColor(new Color(rgb));
		graphics.fillRect(x, y, width, height);
	}

	@Override
	public int getTileHeight() {
		return TILE_SIZE;
	}

	@Override
	public int getTileWidth() {
		return TILE_SIZE;
	}

	@Override
	public int getTilesPerColumn() {
		return TILES_PER_COLUMN;
	}

	@Override
	public int getTilesPerRow() {
		return TILES_PER_ROW;
	}

	@Override
	public void setClip(int x, int y, int width, int height) {
		graphics.setClip(x, y, width, height);
	}
	
	@Override
	public boolean imageUpdate(java.awt.Image img, int infoflags, int x, int y,
			int width, int height) {
		// TODO Auto-generated method stub
		return false;
	}

}
